#-----------------------------------
# VisualK-OS                        
#    Module: Control Console [v3.7] 
#    Author: Kevin Slaughter        
#-----------------------------------

"""
    VisualK-OS Control Console
    Copyright (C)2016  Kevin Slaughter

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

"""
[Major Revision History]
    v3.8: Corrected command line arg checking; I noticed it began bitching about
            parsing an argument of "VKCC.py"... I'm not sure when/why this began
	    appearing, but it is now checked for and stepped around if found.
	    The launching BASH script now uses a GUI and prettier output.
    v3.7: Simplification and general code housekeeping.
    v3.6: Added GPL info/output/triggering-argument.
    v3.5: Split screens into their own modular classes to simplify ScreenManager.
    v3.4: Assertion of standardization across all objects/files.
    v3.3: Further organization, object-oriented structure, misc. optimization.
    v3.2: Split into object-oriented file structure... Main file was >800 lines.
    v3.1: Implementation of no-curses debug mode and serial comms interface.
    v3.0: Rework, implemented ScreenManager
    v2.0: Gamepad implementation
    v1.0: First implementation, subroutine-driven, single file. Very hacky.
"""



#-------------------
# Lib/Header import
#-------------------
from VKCC_Constants import *
import globals, sys, time, os



#-------------------
# Utility functions
#-------------------
### doClientScan(): Detect/handshake with client modules
def doClientScan(bDisplay=False):
	"""
	Performs a scan for all known client devices/slaves. Function
	does not display anything unless bDisplay == TRUE.
	"""

	if(globals.emulateSlaves):
		### Emulating slaves
		# If we're emulating the devices, report them as active/handshook and exit.
		globals.Thor.isAvailable         = True; globals.Thor.isHandshook         = True
		globals.FBA.isAvailable          = True; globals.FBA.isHandshook          = True
		globals.SynthStation.isAvailable = True; globals.SynthStation.isHandshook = True
		return
	else:
		### Not emulating slaves
		# Function does not alter screen contents, unless specified.
		if (bDisplay):
			if not globals.DEBUGMODE:
				globals.SM.changeScreen(SCREEN_SCAN)    # Set screen

				# Bordered screen, no caption. Centered box below.
				globals.SM.menuPrep()
				globals.SM.printText(((globals.MAX_X/2)-7),((globals.MAX_Y/2)-2), "[VisualK-OS]", 9)
				globals.SM.printText(((globals.MAX_X/2)-15),((globals.MAX_Y/2)-1), "Scanning for client modules...", T_ERROR)
				globals.SM.screen.refresh()     # Display immediately

	# Actual detection/assertion
	globals.CB.scanForSlaves(); time.sleep(0.25)

	# Restore previously assigned color theme, if needed
	if (bDisplay):
		if not globals.DEBUGMODE: globals.SM.menuPrep(iOT)
	return


### doExit(): Standardized exit procedures
def doExit(sReason):
	"""
	Depending on the reason given, VKOS_CC attempts to properly
	exit and restore the terminal to its previous state (Assuming
	the session used the Curses UI).\n\n
	"""
	# Close out GamePad device
	if (globals.GP.isAvailable): globals.GP.closeGP()

	# Restore terminal, if using curses UI
	if not globals.DEBUGMODE: globals.SM.restoreConsole();

	# Clear screen and output exit info
	os.system("clear")
	print("[VisualK-OS Control Center]")
	print("------------------------------------------------")
	if(sReason == "LANGWEILIG"):
		print("[!] No tasks... Python findet es so langweilig.")
		print("    --- Exiting.")
	if(sReason == "STACK"):
		print("[!] Exited via screen stack fall-through.")
		print("    - Closed processes and reset terminal.")
		print("[*] Graceful exit, but unplanned.\n")
	if(sReason == "<CTRL+C>"):
		print("[*] Received <Ctrl+C> interrupt.")
		print("    --- Exiting as gracefully as we can.")
	print("------------------------------------------------\n\n")
	sys.exit()

### showGPL(): Displays GPL info in the console.
def showGPL():
	print("VisualK-OS Control Console\nCopyright (C)2016  Kevin Slaughter\n"+\
	      "\nThis program is free software: you can redistribute it and/or\n"+\
	      "modify it under the terms of the GNU General Public License\n"+\
	      "as published by the Free Software Foundation, either version 3\n"+\
	      "of the License, or (at your option) any later version.\n"+\
	      "\nThis program is distributed in the hope that it will be useful,\n"+\
	      "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"+\
	      "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"+\
	      "GNU General Public License for more details.\n"+\
	      "\nYou should have received a copy of the GNU General Public License\n"+\
	      "along with this program. If not, see <http://www.gnu.org/licenses/>.\n")



#--------------------
# Main - Begin here! 
#--------------------
if (__name__=="__main__"):
	### Initialization
	os.system("clear")
	print("[VisualK-OS Control Center - "+globals.VERSION_STR+"]")
	print("----------------------------------\n")

	### Check for command line args
	print("[*] Initializing...")
	print("    - Checking for command-line args...")
	if (len(sys.argv)>=1):
		# Process any args
		for a in range(0, len(sys.argv)):
			if (sys.argv[a] == "NO_CURSES_UI"):
				globals.DEBUGMODE = True
				print("    [arg] {NO_CURSES_UI}")
			elif (sys.argv[a] == "EMULATE_SLAVES"):
				globals.emulateSlaves = True
				print("    [arg] Slave devices will be emulated.")
			elif (sys.argv[a] == "ABOUT"):
				print("    [arg] Got 'ABOUT'. Displaying licensing info...\n")
				showGPL()
				sys.exit()  # Display GPL info and exit.
			elif (sys.argv[a] == "VKCC.py"):
				# Avoid triggering an 'unknown command' warning
				# caused by Python supplying the executing script
				# filename as an argument. Continue onward!
				next
			else:   ### Unknown command line arg
				print("   [arg] Unknown command: \""+sys.argv[a]+"\"")
				time.sleep(3.0) # Stop briefly to alert user
	else:   ### No command line args
		time.sleep(0.1)
	time.sleep(1.0) # Pause for notifications



	### Main program...
	print("\n")
	try:
		### Detect attached slave devices
		if not globals.emulateSlaves:
			print("[*] Detecting slaves...")
			doClientScan(False); time.sleep(0.5);

		### Gamepad I/O initialization
		globals.GP.initGP(); time.sleep(0.5)        

		### Determine display mode
		# NO GUI. Debug mode is console-only, but a gamepad will still work.
		if (globals.DEBUGMODE):
			# Debug mode only uses basic console output.
			globals.SM.changeScreen(SCREEN_DEBUG)   # Prevents stack fall-through
			print("\n>>> Debug mode, no UI to launch.")
			print(">>> Entering main loop...\n")

			# Check for gamepads... With no UI and no gamepad, the system is useless.
			if(globals.GP.numJoysticks==0):
				print("[*] No gamepads or UI... What the fuck are we doing?")
				time.sleep(2.5)
				doExit("LANGWEILIG")

		# Using a GUI
		else:
			# Deal-breaker... If we can't set the terminal
			#   properly, everything goes all fucky. BAIL.
			if (os.environ['TERM'] != "xterm-256color"):	# Assert terminal mode
				print("[!] $TERM must be 'xterm-256color' for curses to work properly.")
				print("- Exiting...");
				sys.exit()

			# Notify, then prepare and display curses UI
			print("\n>>> Launching Curses UI..."); time.sleep(0.5)
			globals.SM.setupCurses()                # Init curses UI
			globals.SM.changeScreen(SCREEN_MAIN)    # Go to main screen



		### Main loop; Go!
		while (globals.SM.curScreen!=SCREEN_NULL):
			if(globals.GP.isAvailable):
				globals.GP.handleEvents()       # Process gamepad events
			if not globals.DEBUGMODE:   ### Only if we're using a GUI
				globals.SM.keyHandler() # Process any keystrokes
				globals.SM.update()	# Redraw, if needed
			time.sleep(0.001)       # Rest for 1ms

		# Exit procedure for if we fall out of the screen stack unexpectedly.
		# Note: Setting the screen to SCREEN_NULL at any point will also trigger this.
		doExit("STACK")

	### Exception Handler: <Ctrl+C>
	except KeyboardInterrupt: doExit("<CTRL+C>")
